
import {LgxVector4D} from "./lgxvector4d";

var degree2Radian = function (degree) {
    return (degree * Math.PI) / 180.0;
}

//行分量为坐标系分量
//x轴：（mData[0][0]，mData[0][1]，mData[0][2]）
//y轴：（mData[1][0]，mData[1][1]，mData[1][2]）
//z轴：（mData[2][0]，mData[2][1]，mData[2][2]）
//原点：（mData[3][0]，mData[3][1]，mData[3][2]）
//对应坐标点描述为行向量，左乘
const ZERO_6E = 0.000001;
class LGXMatrix {
    constructor() {
        this.mData = new Array();
        this.mData = Array.from(Array(4), () => new Array(4));
        this.SetIdentity();
    }


    colone(pOther) {
        for (let r = 0; r < 4; r++) {
            for (let c = 0; c < 4; c++) {
                this.mData[r][c] = pOther.mData[r][c];
            }
        }
    }

    GetVal(rowidx, colidx) {
        return this.mData[rowidx][colidx];
    }

    GetT() {
        let x = this.mData[3][0];
        let y = this.mData[3][1];
        let z = this.mData[3][2];
        let rst = new LgxVector4D();
        rst.setBy4Val(x, y, z, 1);
        return rst;
    }

    GetR() {
        let x = this.mData[3][0];
        let y = this.mData[3][1];
        let z = this.mData[3][2];
        let rst = new LgxVector4D();
        rst.setBy4Val(x, y, z, 1);
        return rst;
    }


    GetS() {
        let vx = this.GetRow(0);
        let sx = vx.Length();

        let vy = this.GetRow(1);
        let sy = vy.Length();

        let vz = this.GetRow(2);
        let sz = vz.Length();
        let rst = new LgxVector4D();
        rst.setBy4Val(sx, sy, sz, 1);
        return rst;
    }


    GetRow(rowidx) {
        let x = this.mData[rowidx][0];
        let y = this.mData[rowidx][1];
        let z = this.mData[rowidx][2];
        let rst = new LgxVector4D();
        rst.setBy4Val(x, y, z, 1);
        return rst;
    }


    GetColumn(colidx) {
        let x = this.mData[0][colidx];
        let y = this.mData[1][colidx];
        let z = this.mData[2][colidx];
        let rst = new LgxVector4D();
        rst.setBy4Val(x, y, z, 1);
        return rst;
    }

    SetIdentity() {
        for (let r = 0; r < 4; r++) {
            for (let c = 0; c < 4; c++) {
                this.mData[r][c] = 0;
            }
        }
        this.mData[0][0] = 1;
        this.mData[1][1] = 1;
        this.mData[2][2] = 1;
        this.mData[3][3] = 1;
    }

    setZero() {
        for (let r = 0; r < 4; r++) {
            for (let c = 0; c < 4; c++) {
                this.mData[r][c] = 0;
            }
        }
    }


    SetT(transV) {
        this.mData[3][0] = transV.x;
        this.mData[3][1] = transV.y;
        this.mData[3][2] = transV.z;
    }
    SetR(oulaRotV) {
        let xrotm = new LGXMatrix();
        let yrotm = new LGXMatrix();
        let zrotm = new LGXMatrix();

        let x = degree2Radian(oulaRotV.x);
        let y = degree2Radian(oulaRotV.y);
        let z = degree2Radian(oulaRotV.z);

        xrotm.mData[1][1] = Math.cos(x);
        xrotm.mData[2][1] = -Math.sin(x);
        xrotm.mData[1][2] = Math.sin(x);
        xrotm.mData[2][2] = Math.cos(x);

        yrotm.mData[0][0] = Math.cos(y);
        yrotm.mData[2][0] = Math.sin(y);
        yrotm.mData[0][2] = -Math.sin(y);
        yrotm.mData[2][2] = Math.cos(y);

        zrotm.mData[0][0] = Math.cos(z);
        zrotm.mData[1][0] = -Math.sin(z);
        zrotm.mData[0][1] = Math.sin(z);
        zrotm.mData[1][1] = Math.cos(z);
        let temp = zrotm.mulOtherMt(yrotm).mulOtherMt(xrotm);
        this.colone(temp);
    }


    SetS(scaleV) {
        let xv = this.GetRow(0);
        let xlen = xv.Length();
        let xration = xlen / scaleV.x;
        this.mData[0][0] /= xration;
        this.mData[0][1] /= xration;
        this.mData[0][2] /= xration;

        let yv = this.GetRow(1);
        let ylen = yv.Length();
        let yration = ylen / scaleV.y;
        this.mData[1][0] /= yration;
        this.mData[1][1] /= yration;
        this.mData[1][2] /= yration;

        let zv = this.GetRow(2);
        let zlen = zv.Length();
        let zration = zlen / scaleV.z;
        this.mData[2][0] /= zration;
        this.mData[2][1] /= zration;
        this.mData[2][2] /= zration;

    }


    coloneCopy() {
        let pOther = new LGXMatrix();
        for (let r = 0; r < 4; r++) {
            for (let c = 0; c < 4; c++) {
                pOther.mData[r][c] = this.mData[r][c];
            }
        }
        return pOther;
    }

    mulVal(pValue) {
        let mtx = new LGXMatrix();
        for (let r = 0; r < 4; r++) {
            for (let c = 0; c < 4; c++) {
                mtx.mData[r][c] = this.mData[r][c] * pValue;
            }
        }
        return mtx;
    }

    divVal(pValue) {
        let mtx = new LGXMatrix();
        for (let r = 0; r < 4; r++) {
            for (let c = 0; c < 4; c++) {
                mtx.mData[r][c] = this.mData[r][c] / pValue;
            }
        }
        return mtx;
    }



    MultT(pVector4) {
        let mat = this;
        let x = pVector4.x * mat.mData[0][0] + pVector4.y * mat.mData[1][0] + pVector4.z * mat.mData[2][0] + mat.mData[3][0];
        let y = pVector4.x * mat.mData[0][1] + pVector4.y * mat.mData[1][1] + pVector4.z * mat.mData[2][1] + mat.mData[3][1];
        let z = pVector4.x * mat.mData[0][2] + pVector4.y * mat.mData[1][2] + pVector4.z * mat.mData[2][2] + mat.mData[3][2];
        let rst = new LgxVector4D();
        rst.setBy4Val(x, y, z, 1);
        return rst;
    }



    negative() {
        let mtx = new LGXMatrix();
        for (let r = 0; r < 4; r++) {
            for (let c = 0; c < 4; c++) {
                mtx.mData[r][c] = -this.mData[r][c];
            }
        }
        return mtx;
    }

    mulOtherMt(mtxIn) {
        let mtx = new LGXMatrix();
        let row = 0;
        let col = 0;
        for (row = 0; row < 4; row++) {
            for (col = 0; col < 4; col++) {
                //为左乘，顶点为行向量
                mtx.mData[row][col] = mtxIn.mData[row][0] * this.mData[0][col]
                    + mtxIn.mData[row][1] * this.mData[1][col]
                    + mtxIn.mData[row][2] * this.mData[2][col]
                    + mtxIn.mData[row][3] * this.mData[3][col];
            }
        }

        return mtx;
    }


    //求逆
    Inverse() {
        let mtx = new LGXMatrix();
        let tDestMat = mtx.mData;
        let tSrcMat = this.mData;
        let det = (tSrcMat[0][0] * (tSrcMat[1][1] * tSrcMat[2][2] - tSrcMat[1][2] * tSrcMat[2][1]) -
		tSrcMat[0][1] * (tSrcMat[1][0] * tSrcMat[2][2] - tSrcMat[1][2] * tSrcMat[2][0]) +
		tSrcMat[0][2] * (tSrcMat[1][0] * tSrcMat[2][1] - tSrcMat[1][1] * tSrcMat[2][0]));
        if (Math.abs(det) < ZERO_6E) {
            return mtx;
        }

        let det_inv = 1.0 / det;

        tDestMat[0][0] = det_inv * (tSrcMat[1][1] * tSrcMat[2][2] - tSrcMat[1][2] * tSrcMat[2][1]);
        tDestMat[0][1] = -det_inv * (tSrcMat[0][1] * tSrcMat[2][2] - tSrcMat[0][2] * tSrcMat[2][1]);
        tDestMat[0][2] = det_inv * (tSrcMat[0][1] * tSrcMat[1][2] - tSrcMat[0][2] * tSrcMat[1][1]);
        tDestMat[0][3] = 0.0; 

        tDestMat[1][0] = -det_inv * (tSrcMat[1][0] * tSrcMat[2][2] - tSrcMat[1][2] * tSrcMat[2][0]);
        tDestMat[1][1] = det_inv * (tSrcMat[0][0] * tSrcMat[2][2] - tSrcMat[0][2] * tSrcMat[2][0]);
        tDestMat[1][2] = -det_inv * (tSrcMat[0][0] * tSrcMat[1][2] - tSrcMat[0][2] * tSrcMat[1][0]);
        tDestMat[1][3] = 0.0; 

        tDestMat[2][0] = det_inv * (tSrcMat[1][0] * tSrcMat[2][1] - tSrcMat[1][1] * tSrcMat[2][0]);
        tDestMat[2][1] = -det_inv * (tSrcMat[0][0] * tSrcMat[2][1] - tSrcMat[0][1] * tSrcMat[2][0]);
        tDestMat[2][2] = det_inv * (tSrcMat[0][0] * tSrcMat[1][1] - tSrcMat[0][1] * tSrcMat[1][0]);
        tDestMat[2][3] = 0.0; 

        tDestMat[3][0] = -(tSrcMat[3][0] * tDestMat[0][0] + tSrcMat[3][1] * tDestMat[1][0] + tSrcMat[3][2] * tDestMat[2][0]);
        tDestMat[3][1] = -(tSrcMat[3][0] * tDestMat[0][1] + tSrcMat[3][1] * tDestMat[1][1] + tSrcMat[3][2] * tDestMat[2][1]);
        tDestMat[3][2] = -(tSrcMat[3][0] * tDestMat[0][2] + tSrcMat[3][1] * tDestMat[1][2] + tSrcMat[3][2] * tDestMat[2][2]);
        tDestMat[3][3] = 1.0; 
        return mtx;
    }
}

export { LGXMatrix }